home *** CD-ROM | disk | FTP | other *** search
/ 17 Bit Software 6: Level 6 / 17 Bit - Level 6 (1998)(Epic Marketing)[!].iso / quartz / q0429.dms / q0429.adf / libray / libobj / geom.c < prev    next >
C/C++ Source or Header  |  1992-05-20  |  9KB  |  445 lines

  1. /*
  2.  * object.c
  3.  *
  4.  * Copyright (C) 1989, 1991, Craig E. Kolb
  5.  * All rights reserved.
  6.  *
  7.  * This software may be freely copied, modified, and redistributed
  8.  * provided that this copyright notice is preserved on all copies.
  9.  *
  10.  * You may not distribute this software, in whole or in part, as part of
  11.  * any commercial product without the express consent of the authors.
  12.  *
  13.  * There is no warranty or other guarantee of fitness of this software
  14.  * for any purpose.  It is provided solely "as is".
  15.  *
  16.  * $Id: geom.c,v 4.0.1.1 91/09/29 15:43:15 cek Exp Locker: cek $
  17.  *
  18.  * $Log:    geom.c,v $
  19.  * Revision 4.0.1.1  91/09/29  15:43:15  cek
  20.  * patch1: GeomBounds now inflates bounds by EPSILON.
  21.  * 
  22.  * Revision 4.0  91/07/17  14:37:47  kolb
  23.  * Initial version.
  24.  * 
  25.  */
  26. #include "geom.h"
  27. #include "list.h"
  28. #include "libcommon/sampling.h"
  29.  
  30. static void GeomBounds(), GeomBoundsAnimated();
  31. void GeomResolveAssoc();    /* probably static */
  32.  
  33. Geom *
  34. GeomCreate(objptr, methods)
  35. GeomRef objptr;
  36. Methods *methods;
  37. {
  38.     Geom *obj;
  39.  
  40.     if (objptr == (GeomRef)NULL)
  41.         return (Geom *)NULL;
  42.         
  43.     obj = (Geom *)share_calloc(1, sizeof(Geom));
  44.     obj->obj = objptr;
  45.     obj->methods = methods;
  46.     obj->animtrans = FALSE;
  47.     obj->trans = obj->transtail = (Trans *) NULL;
  48.     obj->frame = -1;    /* impossible value */
  49.     BoundsInit(obj->bounds);
  50. #ifdef SHAREDMEM
  51.     /*
  52.      * If the counter is in shared memory, processes will
  53.      * be modifying it left-and-right.  So, we cheat and
  54.      * make counter a pointer to a non-shared location and
  55.      * store the value there.
  56.      */
  57.     new->counter = (unsigned long *)Malloc(sizeof(unsigned long));
  58.     *new->counter = 0;
  59. #endif
  60.     return obj;
  61. }
  62.  
  63. /*
  64.  * Return a copy of the given object.
  65.  * Note that surface, texturing, and transformation information
  66.  * is copied by reference.
  67.  */
  68. Geom *
  69. GeomCopy(obj)
  70. Geom *obj;
  71. {
  72.     Geom *new;
  73.  
  74.     new = GeomCreate(obj->obj, obj->methods);
  75.     /* Share texturing, name, #prims, surface info */
  76.     new->name = obj->name;
  77.     new->texture = obj->texture;
  78.     new->surf = obj->surf;
  79.     new->prims = obj->prims;
  80.     new->trans = obj->trans;
  81.     new->animtrans = obj->animtrans;
  82.     new->transtail = obj->transtail;
  83.     /* copy bounds */
  84.     BoundsCopy(obj->bounds, new->bounds);
  85.     return new;
  86. }
  87.  
  88. /*
  89.  * Report bounding box and number of primitives in object.
  90.  */
  91. void
  92. AggregatePrintInfo(obj, fp)
  93. Geom *obj;
  94. FILE *fp;
  95. {
  96.     if (fp) {
  97.         if (obj->name && obj->name[0])
  98.             fprintf(fp,"%s \"%s\":\n", GeomName(obj), obj->name);
  99.         else
  100.             fprintf(fp,"%s:\n", GeomName(obj));
  101.         if (!UNBOUNDED(obj))
  102.             BoundsPrint(obj->bounds, fp);
  103.         fprintf(fp,"\t%lu primitive%c\n",obj->prims,
  104.             obj->prims == 1 ? ' ' : 's');
  105.     }
  106. }
  107.  
  108. /*
  109.  * Convert the given object from a linked list of objects to
  110.  * the desired aggregate type.
  111.  */
  112. int
  113. AggregateConvert(obj, objlist)
  114. Geom *obj, *objlist;
  115. {
  116.     if (!IsAggregate(obj)) {
  117.         RLerror(RL_ABORT, "A %s isn't an aggregate.\n",
  118.             GeomName(obj));
  119.         return 0;
  120.     }
  121.  
  122.     return (*obj->methods->convert)(obj->obj, objlist);
  123. }
  124.  
  125. /*
  126.  * This should really be called
  127.  * GeomInitialize
  128.  * or something.
  129.  */
  130. void
  131. GeomComputeBounds(obj)
  132. Geom *obj;
  133. {
  134.     if (obj->frame == Sampling.framenum)
  135.         return;
  136.  
  137.     if (!obj->animtrans) {
  138.         /*
  139.          * If it isn't animated,
  140.          * just compute bbox directly 
  141.          */
  142.         GeomBounds(obj, obj->bounds);
  143.     } else {
  144.         /*
  145.          * Animated things are gonna get a bbox
  146.          * which is large enough to enclose all
  147.          * the places where the object goes.
  148.          */
  149.         GeomBoundsAnimated(obj);
  150.     }
  151.     /*
  152.      * Enlarge by EPSILON in each direction just to
  153.      * be on the safe side.
  154.      */
  155.     obj->bounds[LOW][X] -= EPSILON;
  156.     obj->bounds[HIGH][X] += EPSILON;
  157.     obj->bounds[LOW][Y] -= EPSILON;
  158.     obj->bounds[HIGH][Y] += EPSILON;
  159.     obj->bounds[LOW][Z] -= EPSILON;
  160.     obj->bounds[HIGH][Z] += EPSILON;
  161.     /*
  162.      * Mark the fact that that the obj is initialized
  163.      * for this frame.
  164.      */
  165.     obj->frame = Sampling.framenum;
  166.     obj->counter = 0;
  167. }
  168.  
  169. static void
  170. GeomBoundsAnimated(obj)
  171. Geom *obj;
  172. {
  173.     int i, m;
  174.     Float newbounds[2][3];
  175.     Float window, subwindow, jitter, subjitter;
  176.  
  177.     /*
  178.      * For each possible screen sample,
  179.      * choose TIME_SUB_SAMPLES times and recompute the
  180.      * bounds of obj at that time,
  181.      * expanding the computed bounding box appropriately.
  182.      */
  183.     BoundsInit(obj->bounds);
  184.     jitter = Sampling.shutter / Sampling.totsamples;
  185.     subjitter = jitter / (Float)TIME_SUB_SAMPLES;
  186.     window = Sampling.starttime;
  187.     for (i = 0; i < Sampling.totsamples; i++, window += jitter) {
  188.         subwindow = window;
  189.         for (m = 0; m < TIME_SUB_SAMPLES; m++, subwindow += subjitter) {
  190.             /*
  191.              * Set the current time.
  192.              */
  193.             TimeSet(subwindow + subjitter*nrand());
  194.             /*
  195.              * Resolve the objects geometric associations
  196.              */
  197.             GeomResolveAssoc(obj);
  198.             /*
  199.              * Compute bounds and expand current bounds.
  200.              */
  201.             GeomBounds(obj, newbounds);
  202.             BoundsEnlarge(obj->bounds, newbounds);
  203.         }
  204.     }
  205.     /*
  206.      * Also sample at time extremes, as for many
  207.      * movements, extremes occur at beginning/end times.
  208.      */
  209.     TimeSet(Sampling.starttime);
  210.     GeomResolveAssoc(obj);
  211.     GeomBounds(obj, newbounds);
  212.     BoundsEnlarge(obj->bounds, newbounds);
  213.  
  214.     TimeSet(Sampling.starttime + Sampling.shutter);
  215.     GeomResolveAssoc(obj);
  216.     GeomBounds(obj, newbounds);
  217.     BoundsEnlarge(obj->bounds, newbounds);
  218. }
  219.  
  220. void
  221. GeomResolveAssoc(obj)
  222. Geom *obj;
  223. {
  224.     /*
  225.      * PrimResolveAssoc(obj);
  226.      */
  227.     TransResolveAssoc(obj->trans);
  228. }
  229.  
  230. /*
  231.  * Set "bounds" of object to be the extent of the primitive.
  232.  */
  233. static void
  234. GeomBounds(obj, bounds)
  235. Geom *obj;
  236. Float bounds[2][3];
  237. {
  238.     Trans *trans;
  239.  
  240.     if (!obj || !obj->methods->bounds)
  241.         RLerror(RL_ABORT, "Can't compute bounds of \"%s\".\n",
  242.             GeomName(obj));
  243.     (*obj->methods->bounds) (obj->obj, bounds);
  244.     bounds[LOW][X] -= EPSILON;
  245.     bounds[LOW][Y] -= EPSILON;
  246.     bounds[LOW][Z] -= EPSILON;
  247.     bounds[HIGH][X] += EPSILON;
  248.     bounds[HIGH][Y] += EPSILON;
  249.     bounds[HIGH][Z] += EPSILON;
  250.     if (obj->trans) {
  251.         for (trans = obj->trans; trans; trans = trans->next)
  252.             BoundsTransform(&trans->trans, bounds);
  253.     }
  254. }
  255.  
  256. char *
  257. GeomName(obj)
  258. Geom *obj;
  259. {
  260.     if (obj->methods->name)
  261.         return (*obj->methods->name)();
  262.  
  263.     return "unknown";
  264. }
  265.  
  266. void
  267. GeomStats(obj, tests, hits)
  268. Geom *obj;
  269. unsigned long *tests, *hits;
  270. {
  271.     if (obj && obj->methods->stats)
  272.         (*obj->methods->stats)(tests, hits);
  273.     else {
  274.         *tests = *hits = 0;
  275.     }
  276. }
  277.  
  278. /*
  279.  * Push an object onto the head of the given stack, returning
  280.  * the new head.
  281.  */
  282. GeomList *
  283. GeomStackPush(obj, list)
  284. Geom *obj;
  285. GeomList *list;
  286. {
  287.     GeomList *new;
  288.     /*
  289.      * Pretty simple.
  290.      * Make new element point to old head and return new head.
  291.      */
  292.     new = (GeomList *)Malloc(sizeof(GeomList));
  293.     new->obj = obj;
  294.     new->next = list;
  295.     return new;
  296. }
  297.  
  298. /*
  299.  * Pop the topmost object off of the given stack, returning the new head.
  300.  * The old head is freed, but the object it points to is not.
  301.  */
  302. GeomList *
  303. GeomStackPop(list)
  304. GeomList *list;
  305. {
  306.     GeomList *ltmp;
  307.  
  308.     ltmp = list->next;    /* Save new head. */
  309.     free((voidstar)list);    /* Free old head. */
  310.     return ltmp;        /* Return new head. */
  311. }
  312.  
  313. Methods *
  314. MethodsCreate()
  315. {
  316.     return (Methods *)share_calloc(1, sizeof(Methods));
  317. }
  318.  
  319. /*
  320.  * Call appropriate routine to compute UV and, if non-null,
  321.  * dpdu and dpdv at given point on the given primitive.  The
  322.  * normal is used to facilitate computation of u, v, and the
  323.  * partial derivatives.
  324.  */
  325. void
  326. PrimUV(prim, pos, norm, uv, dpdu, dpdv)
  327. Geom *prim;
  328. Vector *pos, *norm, *dpdu, *dpdv;
  329. Vec2d *uv;
  330. {
  331.     /*
  332.      * Call appropriate inverse mapping routine
  333.      */
  334.     if (prim->methods->uv == NULL) {
  335.         uv->u = uv->v = 0.;
  336.         if (dpdu) {
  337.             dpdu->y = dpdu->z = 0.;
  338.             dpdu->x = 1.;
  339.         }
  340.         if (dpdv) {
  341.             dpdv->x = dpdv->z = 0.;
  342.             dpdv->y = 1.;
  343.         }    
  344.     } else
  345.         (*prim->methods->uv)(prim->obj,pos,norm,uv,dpdu,dpdv);
  346. }
  347.  
  348. int
  349. PrimNormal(prim, pos, norm, gnorm)
  350. Geom *prim;
  351. Vector *pos, *norm, *gnorm;
  352. {
  353.     /*
  354.      * Call appropriate normal routine
  355.      */
  356.     return (*prim->methods->normal) (prim->obj, pos, norm, gnorm);
  357. }
  358.  
  359. int
  360. PrimEnter(obj, ray, mind, hitd)
  361. Geom *obj;
  362. Ray *ray;
  363. Float mind, hitd;
  364. {
  365.     /*
  366.      * Call appropriate enter/leave routine
  367.      */
  368.     if (obj->methods->enter == NULL) {
  369.         Vector pos, nrm, gnrm;
  370.         /*
  371.          * Sleazy method:  Use hit point, find normal 
  372.          * and take dot prod with ray 
  373.          */
  374.         VecAddScaled(ray->pos, hitd, ray->dir, &pos);
  375.         PrimNormal(obj, &pos, &nrm, &gnrm);
  376.  
  377.         return dotp(&ray->dir, &gnrm) < 0.0;
  378.     }
  379.     else
  380.         return (*obj->methods->enter) (obj->obj, ray, mind, hitd);
  381. }
  382.  
  383. /*
  384.  * Walk through a linked-list of objects.  If the object is unbounded,
  385.  * unlink it it from the list and add it to the 'unbounded' list.
  386.  * If the object is bounded, enlarge the given bounding box if
  387.  * necessary.  Return pointer to unbounded list.
  388.  */
  389. Geom *
  390. GeomComputeAggregateBounds(bounded, unbounded, bounds)
  391. Geom **bounded, *unbounded;
  392. Float bounds[2][3];
  393. {
  394.     Geom *ltmp, *prev, *nextobj;
  395.  
  396.     BoundsInit(bounds);
  397.  
  398.     prev = (Geom *)0;
  399.  
  400.     for (ltmp = *bounded; ltmp; ltmp = nextobj) {
  401.         nextobj = ltmp->next;
  402.         GeomComputeBounds(ltmp);
  403.         if (UNBOUNDED(ltmp)) {
  404.             /*
  405.              * Geom is unbounded -- unlink it...
  406.              */
  407.             if (prev)
  408.                 prev->next = ltmp->next;
  409.             else
  410.                 *bounded = ltmp->next;
  411.             /*
  412.              * And add it to unbounded object list.
  413.              */
  414.             ltmp->next = unbounded;
  415.             unbounded = ltmp;
  416.         } else {
  417.             /*
  418.              * Geom is bounded.
  419.              */
  420.             BoundsEnlarge(bounds, ltmp->bounds);
  421.             prev = ltmp;
  422.         }
  423.     }
  424.     return unbounded;
  425. }
  426.  
  427. /*
  428.  * Find 'highest' animated object on the hitlist.
  429.  */
  430. int
  431. FirstAnimatedGeom(hitlist)
  432. HitList *hitlist;
  433. {
  434.     int i;
  435.  
  436.     for (i = hitlist->nodes -1; i; i--)
  437.         /*
  438.          * If object itself is animated, have
  439.          * to check other flag, too...
  440.          */
  441.         if (hitlist->data[i].obj->animtrans)
  442.             return i;
  443.     return 0;
  444. }
  445.